﻿using SchedulerLite.BLL;
using SchedulerLite.Common;
using SchedulerLite.Model.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace SchedulerLite.Service
{
    public class DelayTaskManager
    {
        private int _loadIntervalCount = 0;
        private int _loadIntervalSeconds = 0;
        TimeWheel _tw;

        public DelayTaskManager(int timeWheelSlotNum)
        {
            _tw = new TimeWheel(timeWheelSlotNum);

            _loadIntervalCount = _loadIntervalSeconds = Config.LoadDelayTaskIntervalSeconds;
        }

        public void LoadTask(DateTime dateTime)
        {
            if (_loadIntervalSeconds > 0)
            {
                if (_loadIntervalCount >= _loadIntervalSeconds)
                {
                    _loadIntervalCount = 0;
                }
                if (_loadIntervalCount == 0)
                {
                    //加载任务
                    var list = B_DelayTask.SelectReadyList(dateTime, dateTime.AddMinutes(1));
                    foreach (var item in list)
                    {
                        _tw.Add(item.Id, item.TriggerTime);
                    }
                }
                _loadIntervalCount++;
            }
        }

        public void TriggerTask(DateTime dateTime)
        {
            //触发
            var delayTaskIds = _tw.WalkStep();
            if (delayTaskIds.Count > 0)
            {
                var taskList = B_DelayTask.SelectByIds(delayTaskIds);
                if (taskList.Count > 0)
                {
                    taskList.AsParallel().ForAll(Run);
                }
            }
        }

        private void Run(DelayTask task)
        {
            HttpClient hc = new HttpClient();
            hc.Timeout = task.TimeoutSeconds == 0 ? TimeSpan.FromSeconds(15) : TimeSpan.FromSeconds(task.TimeoutSeconds);

            Task<HttpResponseMessage> requestTask;
            if (task.Method.Equals("GET", StringComparison.OrdinalIgnoreCase))
            {
                requestTask = hc.GetAsync(task.Url);
            }
            else
            {
                StringContent stringContent = new StringContent(task.PostData, Encoding.UTF8);
                requestTask = hc.PostAsync(task.Url, stringContent);
            }

            requestTask.ContinueWith(reqTask =>
            {
                var log = new ExecuteLog()
                {
                    PostData = task.PostData,
                    TaskId = task.Id,
                    TaskName = task.Name,
                    TaskUrl = task.Url,
                    TaskType = 2,
                    TaskMethod = task.Method,
                };

                if (reqTask.IsFaulted)
                {
                    if (hc != null) hc.Dispose();
                    log.Status = 2;
                    log.Message = reqTask.Exception.GetBaseException().StackTrace;
                    B_ExecuteLog.Add(log);
                    ReJoin(task);
                }
                else if (reqTask.IsCanceled)
                {
                    if (hc != null) hc.Dispose();
                    log.Status = 3;
                    log.Message = "timeout";
                    B_ExecuteLog.Add(log);
                    ReJoin(task);
                }
                else
                {
                    reqTask.Result.Content.ReadAsStringAsync().ContinueWith(readTask =>
                    {

                        if (hc != null) hc.Dispose();
                        if (readTask.Result == task.SuccessFlag)
                        {
                            //删除数据
                            B_DelayTask.Delete(task.Id);
                            log.Status = 1;
                            log.Message = "success";
                            B_ExecuteLog.Add(log);
                        }
                        else
                        {
                            log.Status = 2;
                            log.Message = readTask.Result;
                            B_ExecuteLog.Add(log);
                            ReJoin(task);
                        }
                    });
                }
            });
        }

        private void ReJoin(DelayTask task)
        {
            var flag = B_DelayTask.Retry(task);
            if (flag)
            {
                _tw.Add(task.Id, task.RetrySeconds);
            }
        }
    }
}
